/**
 * Class: PMath
 *
 * Purpose: Math for Processing
 *
 * Created: Jan 20, 2010 @ 4:49:46 PM
 * @author Ken Scott
 */
package org.openfantasia.util.math;

public class Math2D {

	public static double[][] random(double[][] mags) {
		double[][] result = copy(mags);
		for (int i = 0; i < mags.length; i++) {
			result[i] = Math1D.random(result[i]);
		}
		return result;
	}


	public static float[][] random(float[][] mags) {
		float[][] result = copy(mags);
		for (int i = 0; i < mags.length; i++) {
			result[i] = Math1D.random(result[i]);
		}
		return result;
	}


	public static double[][] randomAbs(double[][] mags) {
		double[][] result = new double[mags.length][mags[0].length];
		for (int i = 0; i < mags.length; i++) {
			result[i] = Math1D.randomAbs(mags[i]);
		}
		return result;
	}


	public static float[][] randomAbs(float[][] mags) {
		float[][] result = new float[mags.length][mags[0].length];
		for (int i = 0; i < mags.length; i++) {
			result[i] = Math1D.randomAbs(mags[i]);
		}
		return result;
	}


	public static double[][] abs(double[][] a) {
		double[][] result = new double[a.length][a[0].length];
		for (int i = 0; i < a.length; i++) {
			result[i] = Math1D.abs(a[i]);
		}
		return result;
	}


	public static float[][] abs(float[][] a) {
		float[][] result = new float[a.length][a[0].length];
		for (int i = 0; i < a.length; i++) {
			result[i] = Math1D.abs(a[i]);
		}
		return result;
	}


	public static double[][] add(double[][] a, double[][] b) {
		double[][] result = new double[a.length][a[0].length];
		for (int i = 0; i < a.length; i++) {
			result[i] = Math1D.add(a[i], b[i]);
		}
		return result;
	}


	public static float[][] add(float[][] a, float[][] b) {
		float[][] result = new float[a.length][a[0].length];
		for (int i = 0; i < a.length; i++) {
			result[i] = Math1D.add(a[i], b[i]);
		}
		return result;
	}


	public static double[][] sub(double[][] a, double[][] b) {
		double[][] result = new double[a.length][a[0].length];
		for (int i = 0; i < a.length; i++) {
			result[i] = Math1D.sub(a[i], b[i]);
		}
		return result;
	}


	public static float[][] sub(float[][] a, float[][] b) {
		float[][] result = new float[a.length][a[0].length];
		for (int i = 0; i < a.length; i++) {
			result[i] = Math1D.sub(a[i], b[i]);
		}
		return result;
	}


	public static double[][] mul(double[][] a, double[][] b) {
		double[][] result = new double[a.length][a[0].length];
		for (int i = 0; i < a.length; i++) {
			result[i] = Math1D.sub(a[i], b[i]);
		}
		return result;
	}


	public static float[][] mul(float[][] a, float[][] b) {
		float[][] result = new float[a.length][a[0].length];
		for (int i = 0; i < a.length; i++) {
			result[i] = Math1D.sub(a[i], b[i]);
		}
		return result;
	}


	public static double[][] div(double[][] a, double[][] b) {
		double[][] result = new double[a.length][a[0].length];
		for (int i = 0; i < a.length; i++) {
			result[i] = Math1D.sub(a[i], b[i]);
		}
		return result;
	}


	public static float[][] div(float[][] a, float[][] b) {
		float[][] result = new float[a.length][a[0].length];
		for (int i = 0; i < a.length; i++) {
			result[i] = Math1D.sub(a[i], b[i]);
		}
		return result;
	}


	public static double[][] filter(double[][] src, double[][] kernal) {
		double[][] result = copyFill(src, 0.0f);
		double scale = sum(kernal);
		double r;
		int px, py;

		for (int x = 0; x < src.length; x++) {
			for (int y = 0; y < src[0].length; y++) {
				r = 0f;

				for (int i = 0; i < kernal.length; i++) {
					px = x - i;

					if (px > 0) {
						for (int j = 0; j < kernal[0].length; j++) {
							py = y - j;

							if (py > 0) {
								r += src[px][py] * kernal[i][j];
							}
						}
					}
				}

				result[x][y] = r / scale;
			}
		}

		return result;
	}


	public static float[][] filter(float[][] src, float[][] kernal) {
		float[][] result = copyFill(src, 0.0f);
		float scale = sum(kernal);
		float r;
		int px, py;

		for (int x = 0; x < src.length; x++) {
			for (int y = 0; y < src[0].length; y++) {
				r = 0f;

				for (int i = 0; i < kernal.length; i++) {
					px = x - i;

					if (px > 0) {
						for (int j = 0; j < kernal[0].length; j++) {
							py = y - j;

							if (py > 0) {
								r += src[px][py] * kernal[i][j];
							}
						}
					}
				}

				result[x][y] = r / scale;
			}
		}

		return result;
	}


	public static double[] mix(double[][] matrix) {
		double[] result = Math1D.fill(new double[matrix.length], 0d);
		for (int i = 0; i < matrix.length; i++) {
			result = Math1D.add(result, matrix[i]);
		}
		return result;
	}


	public static double[][] addNoise(double[][] matrix, double frac) {
		double[][] result = new double[matrix.length][matrix[0].length];
		for (int i = 0; i < matrix.length; i++) {
			result[i] = Math1D.addNoise(matrix[i], frac);
		}
		return result;
	}


	public static float[][] addNoise(float[][] matrix, float frac) {
		float[][] result = new float[matrix.length][matrix[0].length];
		for (int i = 0; i < matrix.length; i++) {
			result[i] = Math1D.addNoise(matrix[i], frac);
		}
		return result;
	}


	public static double[][] mulNoise(double[][] matrix, double frac) {
		double[][] result = new double[matrix.length][matrix[0].length];
		for (int i = 0; i < matrix.length; i++) {
			result[i] = Math1D.mulNoise(matrix[i], frac);
		}
		return result;
	}


	public static float[][] mulNoise(float[][] matrix, float frac) {
		float[][] result = new float[matrix.length][matrix[0].length];
		for (int i = 0; i < matrix.length; i++) {
			result[i] = Math1D.mulNoise(matrix[i], frac);
		}
		return result;
	}


	public static double[][] neg(double[][] matrix) {
		double[][] result = new double[matrix.length][matrix[0].length];
		for (int i = 0; i < matrix.length; i++) {
			result[i] = Math1D.neg(matrix[i]);
		}
		return result;
	}


	public static float[][] neg(float[][] matrix) {
		float[][] result = new float[matrix.length][matrix[0].length];
		for (int i = 0; i < matrix.length; i++) {
			result[i] = Math1D.neg(matrix[i]);
		}
		return result;
	}


	public static double[][] scale(double scale, double[][] matrix) {
		double[][] result = copy(matrix);
		for (int i = 0; i < matrix.length; i++) {
			result[i] = Math1D.scale(scale, result[i]);
		}
		return result;
	}


	public static float[][] scale(float scale, float[][] matrix) {
		float[][] result = copy(matrix);
		for (int i = 0; i < matrix.length; i++) {
			result[i] = Math1D.scale(scale, result[i]);
		}
		return result;
	}


	public static double sum(double[][] matrix) {
		double result = 0.0d;
		for (int x = 0; x < matrix.length; x++) {
			result += Math1D.sum(matrix[x]);
		}
		return result;
	}


	public static float sum(float[][] matrix) {
		float result = 0.0f;
		for (int x = 0; x < matrix.length; x++) {
			result += Math1D.sum(matrix[x]);
		}
		return result;
	}


	public static double avg(double[][] matrix) {
		double sum = 0d;
		for (int i = 0; i < matrix.length; i++) {
			sum += Math1D.avg(matrix[i]);
		}
		return sum / (double) matrix.length;
	}


	public static float avg(float[][] matrix) {
		float sum = 0f;
		for (int i = 0; i < matrix.length; i++) {
			sum += Math1D.avg(matrix[i]);
		}
		return sum / (float) matrix.length;
	}


	public static double max(double[][] matrix) {
		double result = 0.0d;
		for (int i = 0; i < matrix.length; i++) {
			double f = Math1D.max(matrix[i]);
			if (f > result) {
				result = f;
			}
		}
		return result;
	}


	public static float max(float[][] matrix) {
		float result = 0.0f;
		for (int i = 0; i < matrix.length; i++) {
			float f = Math1D.max(matrix[i]);
			if (f > result) {
				result = f;
			}
		}
		return result;
	}


	public static double[][] empty(double[][] src) {
		return new double[src.length][src[0].length];
	}


	public static float[][] empty(float[][] src) {
		return new float[src.length][src[0].length];
	}


	public static double[][] copy(double[][] src) {
		double[][] result = empty(src);

		for (int x = 0; x < src.length; x++) {
			result[x] = Math1D.copy(src[x]);
		}

		return result;
	}


	public static float[][] copy(float[][] src) {
		float[][] result = empty(src);

		for (int x = 0; x < src.length; x++) {
			result[x] = Math1D.copy(src[x]);
		}

		return result;
	}


	public static double[][] copyFill(double[][] src, double value) {
		double[][] result = empty(src);
		return fill(result, value);
	}


	public static float[][] copyFill(float[][] src, float value) {
		float[][] result = empty(src);
		return fill(result, value);
	}


	public static double[][] fill(double[][] src, double value) {
		for (int x = 0; x < src.length; x++) {
			for (int y = 0; y < src[0].length; y++) {
				src[x][y] = value;
			}
		}

		return src;
	}


	public static float[][] fill(float[][] src, float value) {
		for (int x = 0; x < src.length; x++) {
			for (int y = 0; y < src[0].length; y++) {
				src[x][y] = value;
			}
		}

		return src;
	}
}